//=============================================================================
// Nuclear Grenade.
//=============================================================================
class TFNKGrenade extends TFProjectile;

var float ExplodeTimer, ExpStart;
var bool bCanHitOwner, bHitWater;
var xEmitter Trail, Smoketrail, chargeSparks;
var() float DampenFactor, DampenFactorParallel;
var class<xEmitter> HitEffectClass;
var class<xEmitter> smoketrailClass;
var float LastSparkTime, health;
var int myteam;

var float seekerThrust;

var() vector ShakeRotMag;           // how far to rot view
var() vector ShakeRotRate;          // how fast to rot view
var() float  ShakeRotTime;          // how much time to rot the instigator's view
var() vector ShakeOffsetMag;        // max view offset vertically
var() vector ShakeOffsetRate;       // how fast to offset view vertically
var() float  ShakeOffsetTime;       // how much time to offset view

replication
{
    reliable if (Role==ROLE_Authority)
        myteam, health, ExplodeTimer, ExpStart, chargesparks, smoketrail;
}

simulated function Destroyed()
{
    if ( Trail != None )
        Trail.mRegen = false; // stop the emitter from regenerating
	if ( SmokeTrail != None )
        SmokeTrail.mRegen = false;
    if ( ChargeSparks != None )
        ChargeSparks.mRegen = false;
    Super.Destroyed();
}

function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
							Vector momentum, class<DamageType> damageType)
{
    if ( Damage > 0 ) health-=damage;
    if( health<=0 ) Explode(Location, vect(0,0,1));
}

simulated function PostBeginPlay()
{
    Super.PostBeginPlay();

    if ( Level.NetMode != NM_DedicatedServer)
    {
        Trail = Spawn(class'TaskForces.TFNKTrail', self,, Location, Rotation);
        trail.SetBase(self);
        smoketrail = Spawn(smoketrailclass, self,, Location, Rotation);
        smoketrail.SetBase(self);
    }

    if ( Role == ROLE_Authority )
    {
        Velocity = Speed * Vector(Rotation);
        RandSpin(10000);
        bCanHitOwner = false;
        if (Instigator.HeadVolume.bWaterVolume)
        {
            bHitWater = true;
            Velocity = 0.6*Velocity;
        }
    }

    settimer(0.1, true);
}

simulated function PostNetBeginPlay()
{
	if ( Physics == PHYS_None )
    {
        explodetimer=level.timeseconds+=5;
    }
}

simulated function Timer()
{
    if(level.timeseconds>=explodetimer)
    {
        ExplodeTimer=99999;

        if (Trail != None )
			Trail.Destroy();
		if (SmokeTrail != None )
			SmokeTrail.Destroy();
		if (ChargeSparks != None )
			ChargeSparks.Destroy();

		BlowUp(location);
    }
    else if(explodetimer!=99999)
    {
        /*if(chargesparks==none)
            chargesparks=Spawn(class'TaskForces.TFNKChargeSparks', self,, Location, Rotation);
        else
        {
            chargesparks.mSizeRange[0]=30+700*(1-(explodetimer-level.TimeSeconds)/5);
            chargesparks.mSizeRange[0]=20+500*(1-(explodetimer-level.TimeSeconds)/5);
        }*/
    }

    /*if(target!=none)
    {
        velocity+=normal(target.Location-location)*seekerthrust;
    }*/
}

simulated function Landed( vector HitNormal )
{
    HitWall( HitNormal, none );
}

simulated function ProcessTouch( actor Other, vector HitLocation )
{
    if(other!=instigator || bcanhitowner) velocity=other.velocity;
}

simulated function HitWall( vector HitNormal, actor Wall )
{
    local Vector VNorm;

    if (explodetimer==99999)
    {
        ExplodeTimer=level.timeseconds+5;
        if (Level.NetMode != NM_DedicatedServer)
			PlaySound(sound'TFMEdia.TFNKCharge',SLOT_None,TransientSoundVolume,,TransientSoundRadius/8);
    }

    // Reflect off Wall w/damping
    VNorm = (Velocity dot HitNormal) * HitNormal;
    Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;

    RandSpin(15000);
    Speed = VSize(Velocity);

    if ( Speed < 20 )
    {
        bBounce = False;
        SetPhysics(PHYS_None);
        if ( Trail != None )
            Trail.mRegen = false; // stop the emitter from regenerating
    }
    else
    {
		if ( (Level.NetMode != NM_DedicatedServer) && (Speed > 250) )
			PlaySound(Impactsound,SLOT_Misc,TransientSoundVolume/2,false,TransientSoundRadius/15);

        if ( !Level.bDropDetail && (Level.DetailMode != DM_Low) && (Level.TimeSeconds - LastSparkTime > 0.5) && EffectIsRelevant(Location,false) )
        {
			Spawn(HitEffectClass,,, Location, Rotator(HitNormal));
            LastSparkTime = Level.TimeSeconds;
        }
    }
}

function BlowUp(vector HitLocation)
{
    local rotator rot;
    local vector loc;
	local int i;
	local TFNKMShroomcloud cloud;

	if ( Role == ROLE_Authority )
	{
	    Spawn(class'TaskForces.TFNukeFlash',,, Location, Rotation);

        loc=location+vect(0,0,1)*512;

        //Mushroom-Cloud
        for(i=0; i<8; i++)
        {
            cloud=none;
            loc=location+vect(0,0,1)*512;
            rot.yaw=(8187)*i;

            cloud=Spawn(class'TaskForces.TFNKMShroomcloud',,,location+vector(rot)*420, Rot);
            cloud.Velocity=vect(0,0,1)*260;
        }

        Spawn(class'TaskForces.TFNKExplosionA',,, Location, rotator(vect(0,0,0)));

        if (Trail != None )
			Trail.Destroy();
		if (SmokeTrail != None )
			SmokeTrail.Destroy();
		if (ChargeSparks != None )
			ChargeSparks.Destroy();

        GotoState('NuclearExplosion');
    }
}

function Explode(vector HitLocation, vector HitNormal)
{
    if ( Role == ROLE_Authority )
		MakeNoise(1.0);
    Spawn(class'Taskforces.TFFlash',,, Location, Rotation);
    Spawn(class'Taskforces.TFNKExp',,, Location, Rotation);

    DmgRadius(vect(100,100,100), 1, 0.20, 100, 400, MyDamageType, MomentumTransfer*0.05, Location);

    PlaySound(sound'TFMedia.TFNKExp',SLOT_None,TransientSoundVolume/1.5,false,TransientSoundRadius/2);

    Destroy();
}

final function DmgRadius(vector flash, float dmgPctHard, float dmgPctThru, float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation )
{
	local actor Victims;
	local float damageScale, dist;
	local vector dir;

	if( bHurtEntry || Role != ROLE_Authority)
		return;

	if(instigator==none)
	{
	    if(pawn(owner)!=none)
            instigator=pawn(owner);
	    else if(instigatorcontroller!=none && instigatorcontroller.pawn!=none)
	        instigator=instigatorcontroller.pawn;
	    else if(controller(owner)!=none && controller(owner).pawn!=none)
	        instigator=controller(owner).pawn;
	}

    bHurtEntry = true;
	foreach CollidingActors( class 'Actor', Victims, DamageRadius, HitLocation )
	{
		// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag
		if( victims!=none && (Victims != self) && (Victims.Role == ROLE_Authority) && (!Victims.IsA('FluidSurfaceInfo')) )
		{
			dir = Victims.Location - HitLocation;
			dist = FMax(1,VSize(dir));
			dir = dir/dist;
			damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);

            if(!fasttrace(Victims.Location, hitlocation)) damagescale*=dmgPctThru;

            if(pawn(victims)!=none) damagescale=damagescale;
            else damagescale*=dmgPctHard;

            if(damage>0)
            {
                Victims.TakeDamage
			    (
				    damageScale * DamageAmount,
				    Instigator,
				    Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir,
				    (damageScale * Momentum * dir),
				    DamageType
			    );

			    if(pawn(victims)!=none && pawn(victims).controller!=none && playercontroller(pawn(victims).controller)!=none && flash!=vect(0,0,0))
                    playercontroller(pawn(victims).controller).clientflash(0.1, flash*damagescale);
		    }
		}
	}
	bHurtEntry = false;
}

state NuclearExplosion
{
	function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
							Vector momentum, class<DamageType> damageType) {}

    function BeginState()
    {
        ShakeView();

        bHidden = true;
		SetPhysics(PHYS_None);
		SetCollision(false,false,false);
        bDynamicLight=true;

		InitialState = 'NuclearExplosion';

        expstart=level.TimeSeconds;
        settimer(0.1, true);
    }

    simulated function timer()
    {
		local float h;
		local TFNKCloudWave wave;

        if(level.TimeSeconds<expstart+2) lightbrightness=(level.timeseconds-expstart)*255;
        else lightbrightness=fmax(0,255-(level.timeseconds-(expstart+2))*26);

        //Cloudwaves
        if(level.TimeSeconds>expstart+2 && level.TimeSeconds<expstart+4 && frand()<0.2)
        {
            h=400+2000*(((level.timeseconds-expstart)-2)/2);

            wave=Spawn(class'TaskForces.TFNKCloudWave',,,Location+vect(0,0,1)*h);
            wave.emitters[0].SizeScale[1].relativesize= 20+(60+rand(40))*(level.timeseconds-(expstart+2))*(1-h/2400);
        }
    }

    function ShakeView()
    {
        local Controller C;
        local PlayerController PC;
        local float Dist, Scale;

        for ( C=Level.ControllerList; C!=None; C=C.NextController )
        {
            PC = PlayerController(C);
            if ( PC != None && PC.ViewTarget != None )
            {
                Dist = VSize(Location - PC.ViewTarget.Location);
                if (Dist<DamageRadius*3)
                {
                    scale=1-(dist/(DamageRadius*3));

                    C.ShakeView(ShakeRotMag*Scale, ShakeRotRate, ShakeRotTime, ShakeOffsetMag*Scale, ShakeOffsetRate, ShakeOffsetTime);
                }
            }
        }
    }

Begin:
    //NeutronFlash
    DmgRadius(vect(10000,11000,12000), 0, 0.9, Damage*0.01, DamageRadius, class'Taskforces.DamTypeNKFlash', MomentumTransfer*0, Location);

    Sleep(0.2);
    PlaySound(sound'TFMedia.TFNKBoom',SLOT_None,5*TransientSoundVolume);

    PlaySound(sound'TFMedia.TFNKRing',SLOT_None,1.0*TransientSoundVolume,false,TransientSoundRadius*1.5,0.3+frand()*0.7);
    PlaySound(sound'TFMedia.TFNKRing',SLOT_None,1.25*TransientSoundVolume,false,TransientSoundRadius*1.6,0.3+frand()*0.5);
    PlaySound(sound'TFMedia.TFNKRing',SLOT_None,1.5*TransientSoundVolume,false,TransientSoundRadius*1.7,0.3+frand()*0.3);

    PlaySound(sound'TFMedia.TFNKDistantBoom',SLOT_None,3*TransientSoundVolume,false,TransientSoundRadius*4);

    //Shockwave+Heat
    DmgRadius(vect(500,400,100), 0.2, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.20, Damage, DamageRadius*0.125, MyDamageType, MomentumTransfer, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.2, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.19, Damage*0.975, DamageRadius*0.213, MyDamageType, MomentumTransfer*0.975, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.2, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.18, Damage*0.9, DamageRadius*0.300, MyDamageType, MomentumTransfer*0.9, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.2, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.17, Damage*0.85, DamageRadius*0.388, MyDamageType, MomentumTransfer*0.85, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.2, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.16, Damage*0.8, DamageRadius*0.475, MyDamageType, MomentumTransfer*0.8, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.15, Damage*0.7, DamageRadius*0.563, MyDamageType, MomentumTransfer*0.7, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.14, Damage*0.6, DamageRadius*0.650, MyDamageType, MomentumTransfer*0.6, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.13, Damage*0.45, DamageRadius*0.738, MyDamageType, MomentumTransfer*0.45, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.12, Damage*0.3, DamageRadius*0.825, MyDamageType, MomentumTransfer*0.3, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.11, Damage*0.1, DamageRadius*0.913, MyDamageType, MomentumTransfer*0.1, Location);
    Sleep(0.2);
    DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/10)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    DmgRadius(vect(0,0,0), 1, 0.10, Damage*0.05, DamageRadius*1.000, MyDamageType, MomentumTransfer*0.05, Location);
    //Heat only
    while(level.TimeSeconds<expstart+13)
    {
        Sleep(0.2);
        DmgRadius(vect(500,400,100), 0.25, 0.50, (Damage/2)*(1-((level.TimeSeconds-expstart)/13)), 0.35*DamageRadius, class'Taskforces.DamTypeNKHeat', MomentumTransfer*-0.2, Location);
    }

    Sleep(5);
    Destroy();
}

defaultproperties
{
     ExplodeTimer=99999.000000
     DampenFactor=0.150000
     DampenFactorParallel=0.300000
     HitEffectClass=Class'XEffects.WallSparks'
     smoketrailClass=Class'taskforces.TFNKSmoketrailR'
     Health=20.000000
     ShakeRotMag=(Z=500.000000)
     ShakeRotRate=(Z=3500.000000)
     ShakeRotTime=6.000000
     ShakeOffsetMag=(Z=20.000000)
     ShakeOffsetRate=(Z=1000.000000)
     ShakeOffsetTime=12.000000
     Speed=1750.000000
     MaxSpeed=2500.000000
     TossZ=0.000000
     Damage=2000.000000
     DamageRadius=7000.000000
     MomentumTransfer=500000.000000
     MyDamageType=Class'taskforces.DamTypeNKShock'
     ImpactSound=Sound'TFMedia.Nuke.TFNKBounce'
     ExplosionDecal=Class'XEffects.RocketMark'
     LightType=LT_Steady
     LightEffect=LE_QuadraticNonIncidence
     LightHue=40
     LightSaturation=192
     LightRadius=128.000000
     DrawType=DT_StaticMesh
     StaticMesh=StaticMesh'XGame_rc.BallMesh'
     Physics=PHYS_Falling
     DrawScale=1.500000
     AmbientGlow=100
     TransientSoundVolume=1.000000
     TransientSoundRadius=5000.000000
     CollisionRadius=4.000000
     CollisionHeight=4.000000
     bProjTarget=True
     bBounce=True
     bFixedRotationDir=True
     DesiredRotation=(Pitch=12000,Yaw=5666,Roll=2334)
}
